package com.haisen.service.impl;

import com.alibaba.fastjson.JSON;
import com.haisen.dataobject.dto.ResourceDto;
import com.haisen.dataobject.entity.Resource;
import com.haisen.dataobject.enums.ResourceType;
import com.haisen.dataobject.mapper.base.ResourceMapper;
import com.haisen.service.ResourceService;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.permission.WildcardPermission;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import tk.mybatis.mapper.weekend.Weekend;
import tk.mybatis.mapper.weekend.WeekendCriteria;

import java.util.*;
import java.util.stream.Collectors;

@Service
@Slf4j
public class ResourceServiceImpl implements ResourceService {

    @Autowired
    private ResourceMapper resourceMapper;

    @Override
    @Transactional
    public void createResource(Resource resource) {
        Resource parent = findOne(resource.getParentId());
        resource.setParentIds(parent.makeSelfAsParentIds());
        resource.setAvailable(true);
        if (resource.getType() == ResourceType.MENU) {
            if (StringUtils.isEmpty(resource.getUrl())) {
                resource.setUrl("#");
            }
        }
        resourceMapper.insertSelective(resource);
    }

    @Override
    @Transactional
    public void updateResource(Resource resource) {
        resourceMapper.updateByPrimaryKeySelective(resource);
    }

    @Override
    @Transactional
    public void deleteResource(Long resourceId) {
        resourceMapper.deleteByPrimaryKey(resourceId);
    }

    @Override
    public Resource findOne(Long resourceId) {
        return resourceMapper.selectByPrimaryKey(resourceId);
    }

    @Override
    public List<ResourceDto> find(Weekend example) {
        List<ResourceDto> resourceDtoList = new ArrayList<>();
        resourceMapper.selectByExample(example).forEach(resource-> {
            resourceDtoList.add(new ResourceDto(resource));
        });
        return resourceDtoList;
    }

    @Override
    public List<ResourceDto> findAll() {
        List<ResourceDto> resourceDtoList = new ArrayList<>();
        resourceMapper.selectAll().forEach(resource-> {
            resourceDtoList.add(new ResourceDto(resource));
        });
        return resourceDtoList;
    }

    /**
     * 根据资源id查找对应权限链接:ization:*, orgization:create |
     * @param resourceIds
     * @return
     */
    @Override
    public Set<String> findPermissions(Set<Long> resourceIds) {
        Set<String> permissions = new HashSet<>();
        /**
         * 发太多sql语句了，优化谢,一条一条的查，或者可以把所有的结果集处理，用stream来处理
         * 这样可以减少发sql的开销
         */
      /*  for (Long resourceId : resourceIds) {
            Resource resource = findOne(resourceId);
            if (resource != null && !StringUtils.isEmpty(resource.getPermission())) {
                permissions.add(resource.getPermission());
            }
        }*/

       Weekend<Resource> example = Weekend.of(Resource.class);
        WeekendCriteria<Resource,Object> criteria = example.weekendCriteria();
        criteria.andIn(Resource::getId, resourceIds);
        List<Resource> resourceList = resourceMapper.selectByExample(example);
        permissions = resourceList.stream().map(Resource :: getPermission)
                .filter((rs)->{
                    if (rs != null && !StringUtils.isEmpty(rs)) return true;
                    else return false;
                })
                .collect(Collectors.toSet());

        return permissions;
    }

    /**
     * permissions user:create  ,user:upate ...
     * 菜单就是资源列表
     * @param permissions
     * @return
     */
    @Override
    public List<ResourceDto> findMenus(Set<String> permissions) {
        //查所有的资源
        Weekend weekend = Weekend.of(Resource.class);
        weekend.setOrderByClause("priority");
        List<Resource> allResources = resourceMapper.selectByExample(weekend);
        List<ResourceDto> menus = new ArrayList<>();
        //资源类型是菜单的,遍历没一项资源
        for (Resource resource : allResources) {
            if (resource.isRootNode()) {
                continue;
            }
            if (resource.getType() != ResourceType.MENU) {
                continue;
            }
            if (!hasPermission(permissions, resource)) {
                continue;
            }
           // log.info("添加菜单:{}",resource.getName());
            menus.add(new ResourceDto(resource));
        }
        return menus;
    }

    /**
     * 是否包含权限,是就把菜单添加上
     * @param permissions
     * @param resource
     * @return
     */
    private boolean hasPermission(Set<String> permissions, Resource resource) {
        // 一级菜单权限没有设置,默认设置可以读取了
        if (StringUtils.isEmpty(resource.getPermission())) {
            return true;
        }
        //permission 也是循环匹配,格式如：user:delete,
        for (String permission : permissions) {
            WildcardPermission p1 = new WildcardPermission(permission);
            WildcardPermission p2 = new WildcardPermission(resource.getPermission());
            if (p1.implies(p2) || p2.implies(p1)) {
               // log.info("授权={},获取资源:{}",permission, resource.getName());
                return true;
            }
        }
        return false;
    }

}
